package main

import (
	"flag"
	"fmt"

	"strings"

	"strconv"

	"errors"

	"encoding/json"

	"time"

	qs "github.com/derekstavis/go-qs"
	"github.com/garyburd/redigo/redis"
	"github.com/go-xorm/xorm"
)

type (
	RedisConf struct {
		Server string
		Pwd    string
		Db     int
		Queue  string
	}
	DataList struct {
		Rooms []int64 `json:"rooms"`
	}
)

func main() {
	var db *string = flag.String("db", "", "<user>:<password>@<protocol>(<ip>:<port>)/<database>?<charset=utf-8>")
	var redis *string = flag.String("redis", "", "<password>@<ip>:<port>/<database>?<queue=*>")
	flag.Parse()
	var redisConf RedisConf
	var err error
	redisConf, err = parseRedisConfig(*redis)
	if err != nil {
		fmt.Println(err.Error())
		return
	}
	fmt.Println("starting...")
	for {
		err = transfer(*db, redisConf)
		if err == nil {
			break
		} else {
			fmt.Println(err)
			time.Sleep(10 * time.Second)
		}
	}
	fmt.Println("goodbye...")
}

func transfer(mysqlUri string, redisConf RedisConf) error {
	var err error
	var mysql *xorm.Engine
	mysql, err = GetMysqlEngine(mysqlUri)
	if err != nil {
		return errors.New("redis connect:" + err.Error())
	}
	var redisPool *redis.Pool = getRedisPool(redisConf)
	var redisConn redis.Conn = redisPool.Get()
	if redisConn.Err() != nil {
		return errors.New("redis connect:" + redisConn.Err().Error())
	}
	var data interface{}
	var dataList DataList = DataList{}
	var room Room
	var orderId int64
	for {
		data, err = redisConn.Do("LPOP", redisConf.Queue)
		if err != nil {
			return errors.New("redis lpop:" + err.Error())
		} else if data == nil {
			time.Sleep(5 * time.Second)
			continue
		}
		json.Unmarshal(data.([]byte), &dataList)
		for _, roomId := range dataList.Rooms {
			room, err = QueryRoom(mysql, roomId)
			if err != nil {
				return errors.New(fmt.Sprintf("room:%d err: %s", roomId, err.Error()))
			}
			orderId, err = room.GetRecentOrderId(mysql)
			if err != nil {
				return errors.New(fmt.Sprintf("room:%d err: %s", roomId, err.Error()))
			} else if orderId == room.OrderId {
				continue
			}
			err = room.SetRecentOrderId(mysql, orderId)
			if err != nil {
				return errors.New(fmt.Sprintf("room:%d err: %s", roomId, err.Error()))
			}
		}
	}
	return nil
}

//解析redis配置
func parseRedisConfig(confStr string) (conf RedisConf, err error) {
	conf = RedisConf{}
	var pwdEndIndex int = strings.Index(confStr, "@")
	var serverEndIndex int = strings.Index(confStr, "/")
	var dbEndIndex int = strings.Index(confStr, "?")
	if pwdEndIndex < 0 || serverEndIndex < 0 || dbEndIndex < 0 {
		err = errors.New("reids URI is wrong")
		return
	}
	conf.Pwd = confStr[0:pwdEndIndex]
	conf.Server = confStr[pwdEndIndex+1 : serverEndIndex]
	conf.Db, _ = strconv.Atoi(confStr[serverEndIndex+1 : dbEndIndex])
	var paramStr string = confStr[dbEndIndex+1:]
	if len(paramStr) <= 0 {
		err = errors.New("reids URI is wrong,need to appoint queue")
		return
	}
	var ok bool
	var params map[string]interface{}
	params, _ = qs.Unmarshal(confStr[dbEndIndex+1:])
	conf.Queue, ok = params["queue"].(string)
	if ok && len(conf.Queue) > 0 {
		return
	} else {
		err = errors.New("reids URI is wrong,need to appoint queue")
		return
	}
}

//获取redis连接池
func getRedisPool(config RedisConf) *redis.Pool {
	return &redis.Pool{
		MaxIdle:     3,
		IdleTimeout: 240 * time.Second,
		Dial: func() (redis.Conn, error) {
			c, err := redis.Dial("tcp", config.Server)
			if err != nil {
				return nil, err
			}
			if _, err := c.Do("AUTH", config.Pwd); err != nil {
				c.Close()
				return nil, err
			}
			if _, err := c.Do("SELECT", config.Db); err != nil {
				c.Close()
				return nil, err
			}
			return c, err
		},
		TestOnBorrow: func(c redis.Conn, t time.Time) error {
			_, err := c.Do("PING")
			return err
		},
	}
}
